package com.tjc.spring.core;

import java.lang.reflect.Constructor;
import java.util.List;

/**
 * @Author: tjc
 * @description
 * @Date Created in 23:09 2021-12-31
 * 找到合适的构造函数，实例化
 */
public class ConstructorResolver {
    private BeanFactory beanFactory;

    public ConstructorResolver(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    public Constructor<?> findConstructor(GenericBeanDefinition bd) {
        return null;
    }

    public Object autowireConstructor(GenericBeanDefinition bd) {
        Constructor<?> constructorToUse = null;
        Object[] argToUse = null;
        Class<?> beanClass = bd.getClazz();

        Constructor<?>[] candidates = beanClass.getConstructors();

        BeanDefinitionValueResolver valueResolver =
                new BeanDefinitionValueResolver(this.beanFactory);
        ConstructArgument cargs = bd.getConstructArgument();
        SimpleTypeConverter typeConverter = new SimpleTypeConverter();
        for (int i = 0; i < candidates.length; i++) {
            Class<?>[] parameterTypes = candidates[i].getParameterTypes();
            if (parameterTypes.length != cargs.size()) {
                continue;
            }
            argToUse = new Object[parameterTypes.length];

            boolean result = this.valuesMatchTypes(parameterTypes, cargs.getValueHolders(), argToUse, valueResolver, typeConverter);
            if (result) {
                constructorToUse = candidates[i];
                break;
            }
        }
        if (constructorToUse == null) {
            throw new RuntimeException(bd.getID() + " can't find a approviate constructor");
        }

        try {
            return constructorToUse.newInstance(argToUse);
        } catch (Exception e) {
            throw new RuntimeException(bd.getID() + " can't create instance");
        }
    }

    private boolean valuesMatchTypes(Class<?>[] parameterTypes, List<ConstructArgument.ValueHolder> valueHolders,
                                     Object[] argToUse, BeanDefinitionValueResolver valueResolver,
                                     SimpleTypeConverter typeConverter) {


        for (int i = 0; i < parameterTypes.length; i++) {
            ConstructArgument.ValueHolder valueHolder = valueHolders.get(i);
            Object originValue = valueHolder.getValue();

            try {
                Object resolveValue = valueResolver.resolveValueIfNecessary(originValue);

                Object convertValue = typeConverter.convertIfNecessary(resolveValue, parameterTypes[i]);
                argToUse[i] = convertValue;
            } catch (Exception e) {
                return false;
            }
        }
        return true;
    }
}
